package com.songtech.server.task;

import com.songtech.server.entry.PushError;
import com.songtech.server.frame.dao.mapper.TerminalSettingMapper;
import com.songtech.server.frame.utils.AnalyzeUtils;
import com.songtech.server.frame.utils.ConfUtils;
import com.songtech.server.task.Initializing.ErrorConfManager;
import com.songtech.server.utils.FormatDateUtils;
import com.songtech.server.utils.GetKeysUtils;
import io.netty.channel.Channel;
import io.netty.channel.ChannelOutboundBuffer;
import org.apache.commons.lang3.StringUtils;
import com.songtech.server.Jedis.JedisBaseDao;
import com.songtech.server.frame.push.Push;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import com.songtech.server.constant.KeysConstant;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Date;
import java.util.TimerTask;

/**
 * Create By YINN on 2018/4/16 8:55
 * Description :
 */

//@Component
public class SettingTimerTask extends TimerTask {

    private final static int MAX_TIME = Integer.valueOf(ConfUtils.get("error.max.times"));


    //    //    @Resource
////    @Qualifier("jedisBaseDaoImpl")
//    @Autowired
    private JedisBaseDao<Serializable> jedisBaseDao;
    //
//    @Autowired
    private Push push;

    //线程id
    private String name;

    /**
     * @param name         线程名称
     * @param jedisBaseDao 这两个接口自动注入 值为空
     * @param push         这两个接口自动注入 值为空
     */
    public SettingTimerTask(String name, JedisBaseDao<Serializable> jedisBaseDao, Push push) {
        this.name = name;
        this.jedisBaseDao = jedisBaseDao;
        this.push = push;
    }

    private final static Logger LOGGER = LoggerFactory.getLogger(SettingTimerTask.class);

    @Override
    public void run() {


        try {

            String msg = (String) jedisBaseDao.lpop(KeysConstant.SETTING);

            System.out.println("定时任务msg:" + msg + "。队列长度:" + jedisBaseDao.size(KeysConstant.SETTING));

            if (StringUtils.isBlank(msg)) {
                return;
            }

            //获取设备唯一身份标识
            String imei = AnalyzeUtils.getIMEI(msg);

            String confirmCmd = AnalyzeUtils.getConfirmCmd(msg);

            //获取队列锁，判断当前imei是否在被锁住
            RedisLock<String> lock = new RedisLock<>(KeysConstant.LOCK_KEY,
                    GetKeysUtils.combineAnyKeys(confirmCmd, imei),
                    msg, jedisBaseDao);

            if (lock.isLock()) {
                return;
            }

            //获取错误信息
            String errorKey = GetKeysUtils.combineAnyKeys(KeysConstant.PUSH_ERROR, imei);
            PushError pushError = (PushError) jedisBaseDao.get(errorKey);

            //判断错误信息是否为空,不为空则直接发送
            if (pushError != null) {

                int presentErrorTimes = pushError.getTimes();

                //超出最大次数限制，则删除此条缓存，终止设置
                if (presentErrorTimes >= MAX_TIME) {

                    //删除推送错误缓存
                    jedisBaseDao.delete(errorKey);

                    //移除锁
                    lock.removeLock();

                } else {

                    long timeDiffMinutes = FormatDateUtils.getSeconds(pushError.getErrorTimeMillis(), System.currentTimeMillis());

                    //判断是否大于 当前次数允许时间差
                    if (timeDiffMinutes > ErrorConfManager.getMinitesDifference(presentErrorTimes)) {

                        send(msg, imei, errorKey, presentErrorTimes, lock);

                    }else {

                        //压回队尾
                        jedisBaseDao.rpush(KeysConstant.SETTING, msg);

                    }

                }

            } else {

                send(msg, imei, errorKey, 0, lock);
            }


        } catch (Exception e) {

            e.printStackTrace();

            LOGGER.error(e.toString());

        }
    }

    /**
     * Created by YINN on 2018/4/20 13:38.
     *
     * @param msg       协议信息
     * @param imei      终端唯一标识
     * @param errorKey  错误信息的redis key
     * @param failTimes 当前失败次数
     * @Description : 推送信息方法
     * @Result : void
     */
    private void send(String msg, String imei, String errorKey, int failTimes, RedisLock lock) {


        //发送并获取netty端是否成功信息
        if (!push.push(msg, imei)) {

            //储存失败信息
            jedisBaseDao.put(errorKey, new PushError(imei, System.currentTimeMillis(), failTimes + 1),3600);

            //压回队尾
            jedisBaseDao.rpush(KeysConstant.SETTING, msg);


        } else {

            //删除错误对象
            jedisBaseDao.delete(errorKey);

        }

        //执行锁，如果锁失败则打印日志
        if (!lock.lock()){

            LOGGER.error("锁key:" + lock.getKey() + "锁失败!");

        }

    }







}
